package club.mzywucai.blog.file_system.upload;

import club.mzywucai.blog.file_system.exception.FileTypeErrorException;
import club.mzywucai.blog.file_system.pojo.domain.JsonData;
import club.mzywucai.blog.file_system.pojo.domain.MakeDir;
import club.mzywucai.blog.file_system.pojo.domain.UploadResult;
import club.mzywucai.blog.file_system.pojo.po.FileInfoPo;
import club.mzywucai.blog.file_system.pojo.vo.UserVo;
import club.mzywucai.blog.file_system.service.RelatedUploadService;
import club.mzywucai.blog.file_system.util.SizeToStringUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.UUID;

/**
 * @author mzywucai
 * @Description
 * @date 2019/1/30
 */
@Data
@PropertySource({"classpath:config/application.properties"})
@WebServlet("/api/user/upload")
public class FileUpload extends HttpServlet {
    private static final long serialVersionUID = 987003232758385500L;

    @Autowired
    RelatedUploadService relatedUploadService;

    /**
     * @Description 缓存中间目录的位置
     */
    @Value("${server.file.tmp}")
    private String tmpPath;
    /**
     * @Description 最大的文件大小：单位B
     */
    @Value("${file.max-size}")
    private Long maxSize;

    @Autowired
    MakeDir mkdir;

    boolean firstCome = true;

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        ObjectMapper mapper = new ObjectMapper();
        PrintWriter writer = response.getWriter();
        String json; //  = mapper.writeValueAsString(user);

        // springboot 通用的拦截器对原生servlet无效，故手动拦截
        HttpSession session = request.getSession();
        UserVo user = (UserVo) session.getAttribute("user");
        if (null == user) {
            json = mapper.writeValueAsString(JsonData.buildError("请先登录再进行操作"));
            writer.write(json);
            writer.flush();

            return;
        }

        if (firstCome) {
            try {
                mkdir.mkdir();
                System.out.println("first come");
            } catch (Exception e) {
                System.out.println("进入异常？");

                json = mapper.writeValueAsString(JsonData.buildError("文件服务器初始化创建文件夹失败！"));
                writer.write(json);
                // return JsonData.buildError("文件服务器初始化创建文件夹失败！");
            }
        }
        firstCome = false;

        String uri = request.getRequestURI();
        String url = request.getRequestURL().toString();
        String host = url.replace(uri, "/");

        boolean flag = false;
        String originName = "";
        String newName = "";
        String suffix = "";
        String fileUrl = "";
        // xxx/yyy/zzz/xxx.zip --> /xxx/yyy/zzz/xxx.zip
        String fileUri = "/";
        String path = "";
        String fileDescribeName = null;
        String fileDescribe = null;
        String fileOriginName = null;
        long fileCategoryLevel2Id = 0L;
        long fileCategoryLevel1Id = 0L;
        String fileSize = null;
        String fileType = null;

        try {
            File tmp = new File(tmpPath);
            if (!tmp.exists()) {
                tmp.mkdirs();
            }
            DiskFileItemFactory factory = new DiskFileItemFactory(10*1024, tmp);
            ServletFileUpload upload = new ServletFileUpload(factory);

            upload.setHeaderEncoding("utf-8");
            String type = request.getHeader("Type");

            String res = relatedUploadService.searchFileInfoRemarkByIdAndLimitLevel1(type);
            if ("error".equals(res)) {
                json = mapper.writeValueAsString(JsonData.buildError("请选择文件类别"));
                writer.write(json);
                writer.flush();

                return;
            }

            type = res;



            // 一个request中最大的容量为maxSize
            upload.setSizeMax(maxSize);
            // 单个文件的最大容量为maxSize
            upload.setFileSizeMax(maxSize);
            // 解析request
            List<FileItem> list = upload.parseRequest(request);
            if(list != null) {


                for(FileItem item: list) {
                    /*
                     * 确定文件项实例是否表示简单窗体字段。
                     * 		如果实例表示简单表单字段，则返回true；
                     * 		如果它表示已上传文件，则为false。
                     */
                    if(item.isFormField()) {
                        // 除文件外的其它表单组件
                        if(item.getFieldName().equals("fileDescribeName")) {
                            fileDescribeName = item.getString("utf-8");
                        }
                        if(item.getFieldName().equals("fileDescribe")) {
                            fileDescribe = item.getString("utf-8");
                        }
                        if(item.getFieldName().equals("fileOriginName")) {
                            fileOriginName = item.getString("utf-8");
                        }
                        if(item.getFieldName().equals("fileCategoryLevel2Id")) {
                            String fileCategoryLevel2IdString = item.getString("utf-8");
                            fileCategoryLevel2Id = Long.parseLong(fileCategoryLevel2IdString);
                        }
                        if(item.getFieldName().equals("fileCategoryLevel1Id")) {
                            String fileCategoryLevel1IdString = item.getString("utf-8");
                            fileCategoryLevel1Id = Long.parseLong(fileCategoryLevel1IdString);
                        }
                        if(item.getFieldName().equals("fileSize")) {
                            fileSize = item.getString("utf-8");
                        }
                        if(item.getFieldName().equals("fileType")) {
                            fileType = item.getString("utf-8");
                        }
                    } else {
                        /*
                         * 注意：
                         * 		限制文件的类型。文件的
                         * 类型(mime-type)：image/*
                         * 只能上传图片
                         */
                        // 得到文件的类型
                        /*String contentType = item.getContentType();
                        if(!contentType.contains("image/")) {
                            throw new FileTypeErrorException("文件类型错误，请换一张图片！");
                        }*/
                        /*
                         * 使用UUID算法，生成唯一的文件名
                         * 避免文件覆盖的问题！
                         */
                        String uuid = UUID.randomUUID().toString();
                        // get到真正的文件名！
                        /*
                         * 这里我们就不用做兼容性的处理了
                         * 因我们只用get一个LastIndexOf(".")
                         * 去获得文件的后缀名，保证文件能够正常的打开！
                         */
                        originName = item.getName();
                        // 获取到后缀名 考虑.tar.gz类似后缀名
                        suffix = getSuffix(originName);
                        // 组合新的文件名
                        newName = uuid + suffix;


                        // 位置：URI+文件名
                        fileUrl = host;

                        if (mkdir.getDocumentURI().equals(type)) {
                            fileUri = fileUri+ mkdir.getTodayDocumentURI();
                            fileUrl = fileUrl + mkdir.getTodayDocumentURI();
                            path = mkdir.getTodayDocumentPath();

                            flag = true;
                        } else if (mkdir.getSystemURI().equals(type)) {
                            fileUri = fileUri+ mkdir.getTodaySystemURI();
                            fileUrl = fileUrl + mkdir.getTodaySystemURI();
                            path = mkdir.getTodaySystemPath();

                            flag = true;
                        } else if (mkdir.getPackageURI().equals(type)) {
                            fileUri = fileUri+ mkdir.getTodayPackageURI();
                            fileUrl = fileUrl + mkdir.getTodayPackageURI();
                            path = mkdir.getTodayPackagePath();

                            flag = true;
                        } else if (mkdir.getAudioURI().equals(type)) {
                            fileUri = fileUri+ mkdir.getTodayAudioURI();
                            fileUrl = fileUrl + mkdir.getTodayAudioURI();
                            path = mkdir.getTodayAudioPath();

                            flag = true;
                        } else {
                            throw new FileTypeErrorException("文件类型错误");
                        }

                        if (null != path) {
                            fileUri = fileUri + newName;
                            fileUrl = fileUrl + newName;
                            path = path + newName;

                            /*
                            File dest = new File(path);
                            file.transferTo(dest);
                            transfer在写入大文件的时候(4G+，出了问题？)
                            System.out.println("dest之后");
                            // flag = true;
                            */
                            // 得到新的目录结构
                            // 生成目录结构
                            File file = new File(path);
                            // 如果不存在这个目录结构！
                            /*if(!file.exists()) {
                                file.mkdirs(); // 这里应该去掉最后的文件名再mkdir，不然的话会把文件名也当中文件夹创建出来。
                                // mkdir只能生成单个目录，所以要用mkdirs
                            }*/
                            //开始文件传输
                            FileUtils.copyInputStreamToFile(item.getInputStream(), file);

                            // 删除item传输的tmp临时文件
                            item.delete();
                        }
                    }
                }
            }
        } catch (FileTypeErrorException e) {
            // 捕获文件类型异常
            json = mapper.writeValueAsString(JsonData.buildError("您上传的文件类型未知"));
            writer.write(json);
            // return JsonData.buildError("您上传的文件类型未知");
        } catch (FileUploadBase.FileSizeLimitExceededException e) {
            // 捕获单个文件大小超规定范围异常
            json = mapper.writeValueAsString(JsonData.buildError("您上传的文件大小超过规定："+ SizeToStringUtil.getSizeString(maxSize)));
            writer.write(json);
            // return JsonData.buildError("您上传的文件大小超过规定："+ SizeToStringUtil.getSizeString(maxSize));
        } catch (FileUploadBase.SizeLimitExceededException e) {
            // 捕获总文件大小超规定范围异常
            json = mapper.writeValueAsString(JsonData.buildError("您上传的文件大小超过规定："+ SizeToStringUtil.getSizeString(maxSize)));
            writer.write(json);
            // return JsonData.buildError("您上传的文件大小超过规定："+ SizeToStringUtil.getSizeString(maxSize));
        } catch (Exception e) {
            json = mapper.writeValueAsString(JsonData.buildError("系统异常"));
            writer.write(json);
            // return JsonData.buildError("系统异常");
        }
        if (flag) {
            FileInfoPo fileInfoPo = new FileInfoPo();
            fileInfoPo.setFileNewName(newName);
            fileInfoPo.setFileDescribeName(fileDescribeName);
            fileInfoPo.setFileDescribe(fileDescribe);
            fileInfoPo.setFileOriginName(fileOriginName);
            fileInfoPo.setFileOriginName(fileOriginName);

            Long userId = user.getUserId();
            fileInfoPo.setUserId(userId);
            fileInfoPo.setFileURI(fileUri);
            fileInfoPo.setFilePath(path);
            fileInfoPo.setFileCategoryLevel2Id(fileCategoryLevel2Id);
            fileInfoPo.setFileSuffix(suffix);
            fileInfoPo.setFileSize(fileSize);
            fileInfoPo.setFileCategoryLevel1Id(fileCategoryLevel1Id);
            fileInfoPo.setFileType(fileType);
            fileInfoPo.setFileURL(fileUrl);

            relatedUploadService.addFileInfo(fileInfoPo);


            UploadResult uploadResult = new UploadResult();
            // origin
            uploadResult.setOriginName(originName);
            // new
            uploadResult.setNewName(newName);
            // suffix
            uploadResult.setSuffix(suffix);
            // fileUrl
            uploadResult.setUrl(fileUrl);
            // fileUri
            uploadResult.setUri(fileUri);
            json = mapper.writeValueAsString(JsonData.buildSuccess(0, uploadResult, "上传成功"));
            writer.write(json);
            // return JsonData.buildSuccess(0, uploadResult, "操作成功");
        } else {
            json = mapper.writeValueAsString(JsonData.buildError("上传失败"));
            writer.write(json);
            // return JsonData.buildError("上传失败");
        }

        writer.flush();
    }

    /**
     * @Description 手动识别后缀
     * @author mzywucai
     * @time 2019-01-31
     * @see 
     * @return   java.lang.String
     * @params  [origin]
     */
    private String getSuffix(String origin) {
        String suffix;
        if (origin.contains(".tar")) {
            suffix = origin.substring(origin.lastIndexOf(".tar"));

        } else if(origin.contains(".")) {
            suffix = origin.substring(origin.lastIndexOf("."));
        } else {
            suffix = "";
        }

        return suffix;
    }
}
